package net.cathackers.devel.scmp.xmpp;

import net.cathackers.devel.scmp.auth.impl.jabber.JabberUserID;
import net.cathackers.devel.scmp.auth.interfaces.UserID;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class Packet {
	protected UserID from_;
	protected UserID to_;
	protected String baseStreamID_ = null;
	protected String id_;
	protected Document codeBehind_;
	protected Element rootElement_;

	protected Packet() {
		codeBehind_ = DocumentHelper.createDocument();
	}

	public Packet(Document doc) {
		setDocument(doc);
	}

	public void setID(String id) {
		rootElement_.addAttribute("id", id);
		id_ = id;
	}

	public String getID() {
		return id_;
	}

	public void setDocument(Document doc) {
		codeBehind_ = doc;
		rootElement_ = codeBehind_.getRootElement();
		if (!rootElement_.getName().equals("presence")) {
		    if(rootElement_.attribute("id") != null)
		    id_ = rootElement_.attribute("id").getStringValue();  
		}
		
	}
	
	public Document getDocument() {
		return codeBehind_;
	} 
	
	public void switchDirection() {
	    UserID tmp = getTo();
	    setTo(getFrom());
	    setFrom(tmp);
	}
	public Element getRootElement() {
	    return rootElement_;
	    
	}
	/**
	 * a classifier that is used to identify the source of the packet
	 * without using its UserID
	 * very useful in cases such as, having the user not being authenticated yet.
	 * and also in cases of digest authentication
	 * @param streamID
	 */
	public void setBaseStreamID(String streamID) {
		baseStreamID_ = streamID;
	}

	public boolean isBaseStreamIDSet() {
		return baseStreamID_ != null;
	}

	public String getBaseStreamID() {
		return baseStreamID_;
	}
	
	public void setTo(UserID to) {
		if (null != to) {
			to_ = to;
			rootElement_.addAttribute("to", to_.getCanonicalName());
		} else {
		    rootElement_.addAttribute("to", null);
		}
	}

	public UserID getTo() {
		UserID ret = null;
		String myTo = rootElement_.attributeValue("to");
		if (null == myTo || 0 == myTo.length()) {
			return null;
		} else {
			// get from cached object if available
			if (null != to_ && myTo.equals(to_.toString())) {
				ret = to_;
			} else {
				// load 'to' attribute into to_
				to_ = new JabberUserID(myTo);
				ret = to_;
			}
		}
		return ret;
	}

	public void setFrom(UserID from) {
		from_ = from;
		if (from == null) {
			rootElement_.addAttribute("from", null);
		} else {
			rootElement_.addAttribute("from", from.getCanonicalName());
		}
	}

	public UserID getFrom() {
		String from = rootElement_.attributeValue("from");
		if (from == null || from.length() == 0) {
			return null;
		} else {
			if (from_ != null && from.equals(from_.toString())) {
				return from_;
			} else {
				from_ = new JabberUserID(from);
				return from_;
			}
		}
	}

	public PacketType getPacketType() {
		String type = rootElement_.getName();
		if (type != null) {
			return PacketType.valueOf(type);
		} else {
			return null;
		}
	}
	
	public void clearContents() {
	    if (rootElement_ != null) {
		rootElement_.clearContent();
	    }
	}
	public StanzaErrors getError() {
		Element error = rootElement_.element("error");
		if (error != null) {
			return new StanzaErrors(error);
		}
		return null;
	}


	public void setError(StanzaErrors error) {
		if (rootElement_ == null) {
			throw new NullPointerException("Error cannot be null");
		}
		// Force the packet type to "error".
		rootElement_.addAttribute("type", "error");
		// Remove an existing error packet.
		if (rootElement_.element("error") != null) {
			rootElement_.remove(rootElement_.element("error"));
		}
		// Add the error element.
		rootElement_.add(error.getElement());
	}

	public String toXML() {
		return rootElement_.asXML();
	}

}
